/* $Id: modal.jquery.js,v 1.1.2.3 2008/07/01 20:04:42 gburns Exp $

Overview:
	jQuery.fn.modal()

Parameters:
	prepend: (String) String to prepend classes/id's
		Default: 'modal'
	width: (Float) Default width for modal (null = no size will be set)
		Default: 400
	height: (Float) Default height for modal (null = no size will be set)
		Default: 300
	opacity: (Float) Opacity for overlay
		Default: 0.8
	speed: (String) Animation speed for modal animations
		Default: 'slow'
	callback: (Function) Function to call after contents
		are loaded into into modal - NOTE: the callback
		function is called on each subsequent jquery.modal.load
		call within the same modal "instance"
	closecallback(closer): (Function) Function to call after modal
		is closed. Passes "closer" to function, which is the element
		that triggered the close.
	center: (Boolean) True centers the modal on the screen
		Default: true
	urlSelector: (String) used for bringing back only a portion
		of the URL specified. See jQuery's load documentation for
		more info.
		Default: null
	closeOnClick: (Boolean) Close the modal if user clicks
		the background.
		Default: true
	onlyOverlay: (Boolean) Only show the page overlay
		Default: false
	zIndex: (Float) z-index of overlay/modal
		Default 10000

Usage:
	JavaScript:
	$('selector').modal();

	If the 'selector' is an ancor tag, the link's location will open
	in a modal. If the selector is a form the form's action will
	open in a modal. If neither, it will search for anchor tags
	and form tags and attach modal methods to them.

	You can also use the jQuery.modal methods directly to incorrporate
	your own plugins:

	$('a#slideshow_link').bind('click', function() {
		$.modal.load(this.href, null, function() {
			$('.slideshow', $.modal.$content).slideshow();
		});
	});

"Magic" Classes:
	{prepend}_close: Anything with the prepend parameter concatinated
		with "_close" will call the jQuery.modal.hide() on click.

Author:
	gburns, modal

TODO:
	documentation
	create multiple instances of modals for various settings
*/

(function($) {
var Modal = function(options) {
	this.settings = options;

	var me = this;
	var $modal_container = $('<div/>').attr({id: me.settings.prepend + 'container'});
	var content_outer_class = me.settings.prepend + 'content_outer';
	var content_class = me.settings.prepend + 'content';
	var $content_outer = $('<div/>').addClass(content_outer_class).css({zIndex: this.settings.zIndex+1, display: 'none'});
	var $content = $('<div/>').addClass(content_class);
	var $body = $('body');
	var overlay = $.overlay.create(options);
	var closing = false;

	var overlay_click = function() {
		if ( me.settings.closeOnClick && !closing ) me.hide();
	};

	overlay.object.bind('click', overlay_click);

	//var $html = $('html');

	$content_outer.css({position: 'absolute'});

	$content_outer.append($content);
	$body.append($content_outer);

	this.showUrl = function(href, params, options) {
		var $response = $('<div/>');
		$response.load(href, params, function() {
			me.showDom($response, options);
		});
	};

	this.showForm = function($form, selector, options) {
		var form = $form[0];

		if ( form.method.toUpperCase() == 'POST' ) {
			me.showUrl(form.action + urlSelector, $this.serializeArray(), options);
		} else {
			var query = (( form.action.indexOf('?') != -1 ) ? '&' : '?') + $form.serialize();
			me.showUrl(form.action + query + selector, null, options);
		}
	};

	this.showDom = function(dom, options) {
		if ( options.copy ) dom = $(dom).clone();
		$content.empty();
		$content.append(dom);
		me.show(options);
	};

	this.showHtml = function(html, options) {
		$content.html(html);
	};

	this.showImage = function(href, options) {
		var img = new Image();

		// once image is preloaded, resize image container
		img.onload = function() {
			/*$.modal.resize({
				width: img.width,
				height: img.height,
				callback: function() {
					$.modal.$content.html(img);
					}
				});*/
			img.onload = function(){}; // clear onLoad, IE behaves irratically with animated gifs otherwise

			//$.modal.$modal
			//	.removeClass(settings.prepend + '_loading');

			//$(img).click($.modal.hide);
			me.showDom(img, options);
		};

		img.src = href;
	};

	this.show = function(options) {
		options = $.extend(me.settings, options || {});

		overlay.show(options);

		if ( closing ) {
			$content_outer.stop(true);
			closing = false;
		} else {
			$content_outer.css({opacity: 0}).show();
		}

		var modal_width = $content_outer.outerWidth(true);
		var modal_height = $content_outer.outerHeight(true);
		var vp = $.viewport.attributes();

		var left = vp.left + vp.width/2 - modal_width/2;
		var top = vp.top + vp.height/2 - modal_height/2;

		if ( top < 0 ) top = 0;
		if ( left < 0 ) left = 0;

		$content_outer.css({left: left, top: top});

		if ( options.speed ) {
			$content_outer.animate({opacity: 1}, options.speed, function() {
				if ( options.callback ) options.callback(me);
			});
		} else {
			$content_outer.css({opacity: 1});
			if ( options.callback ) options.callback(me);
		}
	};

	this.hide = function(options) {
		if ( closing ) return;
		options = $.extend(me.settings, options || {});

		overlay.hide(options);

		if ( options.speed ) {
			closing = true;
			$content_outer.animate({opacity: 0}, options.speed, null, function() {
				$content_outer.hide();
				closing = false;
			});
		} else {
			$content_outer.hide();
		}
	}

	this.content = $content;
};

$.modal = {
	settings: {
		opacity: 0.8,
		speed: 'slow',
		closeOnClick: true,
		zIndex: 10000,

		width: 400,
		height: 300,
		prepend: 'modal_',
		callback: null,
		wrappers: ['n', 's', 'e', 'w', 'nw', 'ne', 'sw', 'se', 'content'],
		closeCallback: null,
		center: true,
		urlSelector: null,

		copy: true
	},
	create: function(options) {
		var options = $.extend(this.settings, options || {});
		var name = 'jQuery::modal::' + options.prepend;
		var modal = this.get(options);;
		if ( !modal ) {
			modal = new Modal(options);
			$.data(document.body, name, modal);
		}
		return modal;
	},
	get: function(options) {
		var options = $.extend(this.settings, options || {});
		var name = 'jQuery::modal::' + options.prepend;
		var modal = $.data(document.body, name);
		return modal;
	},
	show: function(options) {
		var modal = this.create(options);
		modal.show();
		return modal;
	}
};

$.fn.showDomModal = function(options) {
	var modal = $.modal.create(options);

	return this.each(function() {
		modal.showDom(this, options);
	});
};

$.fn.modal = function(options) {
	var modal = $.modal.create(options);
	options = modal.settings;

	var img_search = /(\.jpg|\.jpeg|\.png|\.gif|\.bmp)$/;
	var urlSelector = ( options && options.urlSelector ) ? ' ' + options.urlSelector : '';

	return this.each(function() {
		var $this = $(this);

		if ( this.nodeName == 'A' ) {
			if ( this.href.match(img_search) ) {
				$this
					.bind('click', function() {
						modal.showImage(this.href, options);
						return false;
					});
			} else {
				$this
					.bind('click', function() {
						modal.showUrl(this.href + urlSelector, null, options);
						return false;
					});
			}
		} else if ( this.nodeName == 'FORM' ) {
			// Track which input was used to submit the form and append that to the form data
			var $used_submit;

			$('input[type=submit], input[type=image]', this)
				.bind('click', function() {
					$used_submit = $(this);
				});

			$this
				.bind('submit', function() {
					if ( this.method.toUpperCase() == 'POST' ) {
						var data = $this.serializeArray();

						if ( $used_submit && $used_submit.length && $used_submit.attr('name') ) {
							data[data.length] = {name: $used_submit.attr('name'), value: $used_submit.attr('value')};
						}

						modal.showUrl(this.action + urlSelector, data, options);
					} else {
						var query = (( this.action.indexOf('?') != -1 ) ? '&' : '?') + $this.serialize();
						modal.showUrl(this.action + query + urlSelector, null, options);
					}
					return false;
				});
		}
	});
}
})(jQuery);